home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS Toolkit
/
BBS Toolkit.iso
/
windows
/
xmdmdlp.zip
/
XMODEM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-10
|
26KB
|
869 lines
/************************************************************************/
/* */
/* XMODEM.DLP */
/* */
/* This is a sample (DLP) DLL to implement the XMODEM protocol */
/* */
/* Four calls are made to the (DLP) by PW.EXE */
/* GET_DLL_CAPS( LPSTR ) */
/* ADVANCED_DLL( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR ) */
/* STARTDLL_XFER( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR, int, int ) */
/* DLL_XFER( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR, int ) */
/* */
/* PROTOSET is a struct of PW.EXE variables which the protocol can */
/* use. It also contains callback fuctions for all the */
/* communication functions necessary to implement a */
/* protocol. A large global buffer is already allocated */
/* (10240 bytes) and pd->bigptr is a locked pointer to this */
/* memory. 66 extra bytes are contained in the struct to */
/* be cast and used by the (DLP) as required. Reference */
/* XMODEM.H. The (DLP) should use this area for any global */
/* variables it requires, thus supporting mulitple instances */
/* use of the protocol. */
/* */
/* MAINSET is a struct of PW.EXE variables of a more general nature */
/* which the protocol can use. Reference XMODEM.H. */
/* */
/* ADVANCED_DLL, STARTDLL_XFER, & DLL_XFER are all passed a LPSTR to */
/* 3 bytes of exta data which is intended to be used for */
/* advanced settings. */
/* */
/* Note: To allow aspect to determine sucess or failure of the */
/* protocol *(pd->aspfxfer) should be set to equal to */
/* ASP_PROT_FAIL on entry and set to ASP_PROT_SUCCESS on */
/* termination if successful. */
/* */
/************************************************************************/
/************************************************************************/
/* */
/* This sample is provided as a service to you. DATASTORM does not in */
/* any way warrant the source code, nor do we commit to any support on */
/* this sample file. */
/* */
/************************************************************************/
#define _WINDOWS
#define _WINDLL
#include <windows.h>
#include <string.h>
#include <io.h>
#include <dos.h>
#include "xmodem.h"
//▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
//▓▓
//▓▓ global variables used by xmodem.dlp
//▓▓
//▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
char szBuffer[128];
PROTOSET FAR *pd;
MAIN FAR *mn;
HWND hWnd;
HANDLE hInst;
ADVANCEDSET adv;
//▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
//▓▓
//▓▓ 1. DLL entry and exit routines
//▓▓
//▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
//--------------------------------------------------------------------------
//
// LibMain() - DLL entry function
//
//--------------------------------------------------------------------------
BOOL FAR PASCAL LibMain(hInstance, wDataSeg, cbHeapSize, lpszCmdLine)
HANDLE hInstance;
WORD wDataSeg;
WORD cbHeapSize;
LPSTR lpszCmdLine;
{
hInst = hInstance; // save instance handle for dialog box and resources
if(cbHeapSize !=0 )
UnlockData(0);
return(1);
}
//--------------------------------------------------------------------------
//
// WEP() - DLL termination function
//
// Notes: 1. WEP may not be called when the DLL closes and therefore
// cannot be counted on to perform termination tasks.
//
//--------------------------------------------------------------------------
void FAR PASCAL WEP(nParamater)
int nParamater;
{
return;
}
/**********************************************************************/
/* */
/* GET_DLL_CAPS */
/* */
/* This procedure is called by PW.EXE when a new (DLP) file is */
/* found in the PW.EXE directory. The (DLP) is to return the */
/* bitflags of its capablities. */
/* */
/* DLL_CAP_SHOWXFER-requests PW.EXE to show its normal xfer dlg box */
/* DLL_CAP_MULTISEND-(DLP) is capable of sending multiple files */
/* DLL_CAP_AUTODOWNLOAD-(DLP) is capable of autodowloading files */
/* DLL_CAP_PWOPENFILE-requests PW.EXE to open the inital file */
/* DLL_CAP_RCVNEEDNAME-PW.EXE is to prompt user for a rcv file name */
/* DLL_CAP_ADVANCED-(DLP) has advanced dialog box for user setup */
/* */
/* If (DLP) return DLL_CAP_AUTODOWNLOAD, then the auto detect string */
/* (null terminated, 11 char max.) should be copied to lptr */
/* passed into the function. */
/* */
/**********************************************************************/
WORD FAR PASCAL GET_DLL_CAPS( lptr )
LPSTR lptr;
{
WORD i = 0;
return( i | DLL_CAP_ADVANCED | DLL_CAP_RCVNEEDNAME );
// lstrcpy( lptr,"0x1b0x1b"); // if autodownload capable
// return( i | DLL_CAP_AUTODOWNLOAD | DLL_CAP_ADVANCED | DLL_CAP_RCVNEEDNAME );
}
/**********************************************************************/
/* */
/* ADVANCED_DLL */
/* */
/* This procedure is called by PW.EXE when the (DLP) has return the */
/* DLL_CAP_ADVANCED capablity flag and the user has selected the */
/* advanced menu (or dblclicked on the protocol button). */
/* it is intened to allow the (DLP) to provide a Dialog box for */
/* advanced options. */
/* */
/* Note: This is a dummy routine, for example only */
/* */
/**********************************************************************/
void FAR PASCAL ADVANCED_DLL( inpd, inmn, hwnd, extra )
PROTOSET FAR *inpd;
MAIN FAR *inmn;
HWND hwnd; // handle to the parent window, for dialog box
LPSTR extra; // 3 Bytes of information for advanced setup
{
FARPROC lpproc;
adv = *(ADVANCEDSET FAR *)extra;
lpproc = MakeProcInstance(SetupDlgProc, hInst );
DialogBox(hInst,"SETUP",hwnd,lpproc );
FreeProcInstance( lpproc );
*(ADVANCEDSET FAR *)extra = adv;
}
/**********************************************************************/
/* */
/* STARTDLL_XFER */
/* */
/* Allows (DLP) to initialize variables and start the actual xfer. */
/* send = TRUE if sendin a file, FALSE receiving a file */
/* from_auto = TRUE if called from auto detect sequence */
/**********************************************************************/
int FAR PASCAL STARTDLL_XFER( inpd, inmn, hwnd, extra, send, from_auto)
PROTOSET FAR *inpd;
MAIN FAR *inmn;
HWND hwnd;
LPSTR extra;
int send;
int from_auto;
{
pd = inpd;
mn = inmn;
// if(from_auto) // if auto detect the initialize
// {
// lstrcpy( pd->szTempDir,"d:\\pw");
// lstrcpy( pd->szTempName,"temp.gif");
// }
if(!FileRxTX(send, pd->szTempName ))
{
(*pd->EndXfer)();
return(FALSE);
}
// Init. global varables ---------------------------------------------------
pd->rec_len = 128;
pd->xcount = 132;
pd->datalen = 0;
pd->Aborting = 0;
pd->no_char_wait = 1000;
pd->retries = 3;
pd->runcnt = 0;
pd->xcount = 0;
// -------------------------------------------------------------------------
if(pd->bdiag) // if requested show xfer box, ASPECT can request this to be FALSE
{
(*pd->ShowXferBox)(send); // Call PW.EXE function to show xfer box
SetWindowText( pd->hDlg1,"DLL [XModem]");
}
if(send)
{
pd->pcstate = IDX_WAITACK; // set state to show we are sending
pd->bbegin = 1;
pd->end_record = 255;
}
else // receiving
{
pd->pcstate = IDX_RXING; // set state to show we are receiving
pd->bbegin = 2;
pd->rec_no = 1; // initialize record count
pd->end_record = 0;
pd->xwaittime = GetTickCount()+10000; // set timout to 10 seconds
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1); // start with NACK
}
return(TRUE);
}
/**********************************************************************/
/* */
/* DLL_XFER */
/* */
/* Called every timer tick (~55msecs) */
/**********************************************************************/
int FAR PASCAL DLL_XFER(inpd, inmn, hwnd, extra, send)
PROTOSET FAR *inpd;
MAIN FAR *inmn;
HWND hwnd;
LPSTR extra;
int send;
{
pd = inpd;
mn = inmn;
switch(pd->pcstate) // switch on xfer state
{
case IDX_RXING:
RXING();
break;
case IDX_NOCHAR:
NOCHAR();
break;
case IDX_WAITACK:
WAITACK();
break;
}
return(TRUE);
}
//▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
//█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█
//▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
//█▓█▓ ▓█▓█
//▓█▓█ █▓█▓
//█▓█▓ L O C A L R O U T I N E S ▓█▓█
//▓█▓█ █▓█▓
//█▓█▓ ▓█▓█
//▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
//█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█
//▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
BOOL FAR PASCAL SetupDlgProc( hDlg, message, wParam, lParam )
HWND hDlg;
WORD message;
WORD wParam;
LONG lParam;
{
switch (message)
{
case WM_INITDIALOG:
CheckDlgButton( hDlg, 10, (adv.fRcvFileSelect?0:1));
CheckDlgButton( hDlg, 11, (adv.fSendFileSelect?0:1));
CheckRadioButton( hDlg, 20, 21, 20+(adv.fChecksum?1:0));
CheckRadioButton( hDlg, 30, 31, 30+(adv.fRecLength128?1:0));
return(TRUE);
case WM_COMMAND: // the only command is OK
if(wParam != 1)
return(FALSE);
adv.fRcvFileSelect = IsDlgButtonChecked( hDlg,10)?0:1;
adv.fSendFileSelect = IsDlgButtonChecked( hDlg,11)?0:1;
adv.fChecksum = IsDlgButtonChecked( hDlg,21)?1:0;
adv.fRecLength128 = IsDlgButtonChecked( hDlg,31)?1:0;
EndDialog( hDlg, TRUE );
break;
default:
return( FALSE );
}
return( TRUE );
}
void RXING()
{
LPSTR lptr;
int i,j;
if(pd->bCancel) // set when user presses cancel on the xfer box
{
if(pd->hDlg1) // if xfer box is diplayed, show "Aborting by user"
LastError(4);
End_It(17);
return; // we have cancel pressed so terminate */
}
if( GetTickCount() > pd->xwaittime) // we timed-out?
{
if(pd->hDlg1)
LastError(1);
if(pd->bbegin==2) // we have not started xfer yet, if retries is OK send another NACK
{
if(--pd->retries == 0)
{
End_It(14);
return;
}
(*pd->WriteCommW) ( (HANDLE)mn->hCid, (LPSTR)"\x15", (int)1);
pd->xwaittime = GetTickCount()+10000;
return;
}
else if(pd->bbegin == 99) // special case, we timed out after sending EOF, and not received NACK
{
if(_lwrite( pd->hCommFile, pd->bigbuff, (WORD)(pd->bigptr-pd->bigbuff)) != (WORD)(pd->bigptr-pd->bigbuff))
StatusLine(IDS_LASTERROR+19,NULL); // Show error writing file
else
StatusLine(IDS_LASTERROR+14,pd->szRcvFile); // Completed Xfer
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1); /* this is ack sent after we sent a nack but got no responce and protocol != batch stuff */
*pd->aspfxfer = ASP_PROT_SUCCESS;
(*pd->EndXfer)(); // leave xfer
return;
}
else
{
pd->xwaittime = GetTickCount()+20000;
if(pd->bbegin > 2)
pd->bbegin +=1;
else
pd->bbegin = 3;
if(pd->bbegin == 5)
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);
return;
}
}
switch(GetXRecord())
{
case IDX_RXING:
break;
case IDX_ACK:
if(((BYTE)pd->rec_no == (BYTE)*(pd->cbuff+1)) && ((BYTE)(*(pd->cbuff+2)+pd->rec_no) == 255))
{
lptr = pd->cbuff;
lptr += 3;
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);
//▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
// If we're not in a gif state and we want to be
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
if(!mn->gifstate && pd->should_gif)
{
//▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
// If this is the first block
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
if (pd->runcnt == 0)
{
AnsiLower((LPSTR)pd->szRcvFile);
if(_fstrstr(pd->szRcvFile,".gif"))
(*pd->startgif)();
}
}
for(i=0;i<pd->rec_len;i++)
{
if(mn->gifstate)
{
j = (*pd->FeedDisplay)((BYTE)*lptr);
if(!j)
{
StatusLine(IDS_LASTERROR+36,pd->szRcvFile);
if (!pd->hDlg1 && pd->bdiag)
{
(*pd->ShowXferBox)(0); // show xfer box for recieve
SetWindowText( pd->hDlg1,"DLL [XModem]");
SetDlgItemText(pd->hDlg1, ID_FILENAME,AnsiLower(pd->szRcvFile));
}
}
}
*pd->bigptr++ = *lptr++;
}
//▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
// If we're not doing gifs and we
// don't have a status box up
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
if (!mn->gifstate)
{
if (!pd->hDlg1 && pd->bdiag)
{
(*pd->ShowXferBox)(0); // show xfer box for recieve
SetWindowText( pd->hDlg1,"DLL [XModem]");
SetDlgItemText(pd->hDlg1, ID_FILENAME,AnsiLower(pd->szRcvFile));
}
}
if(pd->bigptr == (pd->bigbuff+10240))
{
if(_lwrite( pd->hCommFile, pd->bigbuff, 10240 ) != 10240)
{
End_It(20);
return;
}
pd->bigptr = pd->bigbuff;
}
pd->rec_no +=1;
pd->rec_no &= 0xff;
pd->runcnt += pd->rec_len;
if(pd->hDlg1)
{
wsprintf(szBuffer,"%lu",pd->runcnt);
SetDlgItemText(pd->hDlg1,ID_BLKNO, szBuffer);
LastError(0);
}
pd->pcstate = IDX_RXING;
}
/* bad record routine */
else if(((BYTE)(pd->rec_no-1) == (BYTE)*(pd->cbuff+1)) && ( (BYTE)(*(pd->cbuff+2)+pd->rec_no-1) == 255))
{
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);
if(pd->hDlg1)
{
SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
if(pd->nackcount > 20)
pd->bCancel = 2;
LastError(7);
}
pd->pcstate = IDX_RXING;
}
else if(pd->rec_no == 0)
End_It(24);
else
End_It(19);
pd->xwaittime = GetTickCount()+20000;
pd->xcount = 0;
return;
case IDX_NOCHAR:
if(pd->bCancel)
{
if(pd->hDlg1)
LastError(4);
End_It(17);
return; /* we have cancel pressed so terminate */
}
pd->xcount = pd->bbegin = 0;
pd->xwaittime = GetTickCount() + pd->no_char_wait;
return;
case IDX_EOT:
if(pd->bbegin != 99) // first send a nack to make sure it was a valid EOT*/
{
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);
pd->bbegin = 99;
pd->pcstate = IDX_RXING;
pd->xwaittime = GetTickCount()+2000; // just wait 2 seconds for this to happen */
}
else
{
if(_lwrite( pd->hCommFile, pd->bigbuff, (WORD)(pd->bigptr-pd->bigbuff)) != (WORD)(pd->bigptr-pd->bigbuff))
StatusLine(IDS_LASTERROR+19,NULL); /* Show error writing file */
else
StatusLine(IDS_LASTERROR+14,pd->szRcvFile); /* Completed Xfer */
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);
*pd->aspfxfer = ASP_PROT_SUCCESS;
(*pd->EndXfer)();
}
return;
default:
return;
}
}
void WAITACK()
{
if(pd->bCancel && !pd->Aborting) // set so user knows we are pd->Aborting
{
pd->Aborting = TRUE;
*pd->aspfxfer = ASP_PROT_FAIL; // pointer to aspect file xfer flag
if(pd->hDlg1)
LastError(4);
if(pd->bbegin==1)
End_It(17);
return; /* we have cancel pressed so terminate */
}
if( GetTickCount() > pd->xwaittime )
{
if(pd->rec_no != pd->end_record) // if they are equal we have good Xfer
{
End_It(1);
return;
}
(*pd->EndXfer)();
return;
}
switch(WaitingForAck())
{
case IDX_TERMINATE:
End_It(13);
return;
case IDX_WAITACK:
return;
case IDX_ACK:
if(pd->bCancel)
{
End_It(17);
return;
}
ymodem_tx();
pd->xwaittime = GetTickCount()+20000;
}
}
void NOCHAR()
{
if(pd->bCancel)
{
*pd->aspfxfer = ASP_PROT_FAIL; // pointer to aspect file xfer flag
if(pd->hDlg1)
LastError(4);
}
if(!MoreCharacters())
pd->xwaittime = GetTickCount() + pd->no_char_wait;
else if(GetTickCount() > pd->no_char_wait)
{
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);
pd->xwaittime = GetTickCount()+20000; // 20 seconds
pd->pcstate = IDX_RXING;
}
}
// Place a message on PW.EXE statusline
void StatusLine(index,lptr)
WORD index;
LPSTR lptr;
{
char line[128];
LoadString( hInst,index,line,80); // get resource string
if(lptr)
lstrcat(line,lptr);
(*pd->StatusLineDirect) ( (LPSTR)line); // call statusline function in PW.EXE
}
void LastError(i)
int i;
{
char line[21];
if(pd->hDlg1)
{
if(i)
LoadString( hInst, IDS_LASTERROR+i-1, (LPSTR)line, 20);
else
line[0] = 0;
SetDlgItemText( pd->hDlg1,ID_UARTERR,(LPSTR)line);
}
}
void End_It(i)
int i;
{
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x18\x18\x18\x18\x18\x18\x18\x18\x08\x08\x08\x08\x08\x08\x08\x08",(int)16);
StatusLine(IDS_LASTERROR+i-1,NULL);
*pd->aspfxfer = ASP_PROT_FAIL; // pointer to aspect file xfer flag
(*pd->EndXfer)();
}
void StartXRecord(dlen, data)
int dlen;
LPSTR data;
{
LPSTR s;
int i,crc;
s=pd->cbuff;
pd->datalen = dlen;
pd->rec_no +=1;
*s++ = 1;
*s++ = (BYTE)(pd->rec_no);
*s++ = (BYTE)(255-pd->rec_no);
(*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)(s-3),(int)3);
crc = 0;
for(i=0; i<pd->rec_len;i++)
{
*s=*data;
crc += *data++;
(*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)s++, (int)1);
}
*s = LOBYTE(crc);
(*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)s,(int)1);
pd->pcstate=IDX_WAITACK;
}
int WaitingForAck()
{
char recvchar[1];
if( (*pd->GetCommErrorW) ((HANDLE)mn->hCid))
{
while( (*pd->GetCommErrorW) ((HANDLE)mn->hCid));
(*pd->FlushCommW) ( (HANDLE)mn->hCid, (int)1); /* flush recieve que */
if(pd->hDlg1)
{
SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
if(pd->nackcount > 20)
pd->bCancel = 2;
LastError(8);
}
}
else if(mn->comstat.cbInQue >= 1)
{
(*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)recvchar,(int)1);
if(*recvchar == ACK)
pd->pcstate = IDX_ACK;
else if((*recvchar == NAK) && !pd->bbegin)
{
if(pd->bCancel)
return(pd->pcstate = IDX_ACK);
(*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)0);
(*pd->WriteCommW) ( (HANDLE)mn->hCid, (LPSTR)pd->cbuff, (int)pd->xcount);
if(pd->hDlg1)
{
SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
if(pd->nackcount > 20)
pd->bCancel = 2;
LastError(6);
}
}
else if(*recvchar == CANCEL)
{
(*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)0);
pd->pcstate = IDX_TERMINATE;
}
else if((*recvchar == NAK) && (pd->bbegin == 1))
{
if(pd->bCancel)
return(pd->pcstate = IDX_ACK);
else
pd->xcount = 132;
pd->pcstate = IDX_ACK;
pd->bbegin = 0;
}
else (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)1);
}
return(pd->pcstate);
}
int GetXRecord()
{
short i;
int j,k,l;
if(pd->rcnt>(3*pd->xcount)/4 && pd->xcount)
k=4;
else
k=1;
for(j=0;j<k;j++)
{
l = (*pd->GetCommErrorW) ((HANDLE)mn->hCid);
if(l)
{
while((*pd->GetCommErrorW) ((HANDLE)mn->hCid));
i = 8;
error_state:
if(pd->hDlg1)
{
SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
if(pd->nackcount > 20)
pd->bCancel = 2;
LastError(i);
}
return(pd->pcstate = IDX_NOCHAR);
}
if((mn->comstat.cbInQue >= 1) && (pd->xcount == 0))
{
if(pd->bbegin && pd->bbegin != 99)
{
pd->bbegin = 0;
pd->xwaittime = GetTickCount()+2000;
}
(*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)pd->cbuff,(int)1);
if(pd->cbuff[0] == 1)
{
pd->rec_len = 128;
pd->xcount = 128+3;
}
else if(pd->cbuff[0] == EOT)
pd->pcstate = IDX_EOT;
else if(pd->cbuff[0] == CANCEL)
{
StatusLine(IDS_LASTERROR+12,NULL);
(*pd->EndXfer) ();
return(0);
}
else
{
i = 10;
goto error_state;
}
pd->crc = 0;
mn->comstat.cbInQue -=1;
pd->rcnt = 0;
}
if(mn->comstat.cbInQue && pd->xcount )
{
for(i=0; i<(int)mn->comstat.cbInQue; i++ )
{
(*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)(pd->cbuff+pd->rcnt+1),(int)1);
if(++pd->rcnt<3) continue;
else if( pd->rcnt < pd->xcount )
pd->crc += pd->cbuff[pd->rcnt];
if(pd->rcnt != pd->xcount) continue;
if((BYTE)*(pd->cbuff+pd->xcount)==LOBYTE(pd->crc))
pd->pcstate = IDX_ACK;
else
{
i=2; goto error_state;
}
}
}
}
return(pd->pcstate);
}
BOOL MoreCharacters()
{
(*pd->GetCommErrorW) ((HANDLE)mn->hCid);
if( mn->comstat.cbInQue != 0)
{
(*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)1);
return(FALSE);
}
else return(TRUE);
}
void ymodem_tx()
{
int nbytes;
LPSTR lptr;
int i;
LastError(0);
go_again:
if(pd->rec_no == pd->end_record ) // we are at end of file we transmitt a EOT! wait for it to be acked
{
if(pd->bpos)
{
(*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x4",(int)1); // send EOF and be ready to re-tx if nack
pd->xcount = 1;
*pd->cbuff = '\x4';
pd->pcstate = IDX_WAITACK;
pd->bpos = 0;
return;
}
else
{
StatusLine(IDS_LASTERROR+14,pd->szRcvFile); // Completed Xfer
(*pd->EndXfer)();
return;
}
}
if( pd->bigptr == (pd->bigbuff+10240) )
{
nbytes = _lread( pd->hCommFile, pd->bigbuff, 10240);
if(!nbytes)
{
pd->end_record = pd->rec_no = pd->bpos = 1; // this is to let the if statements pass through */
goto go_again;
}
pd->bigptr = pd->bigbuff;
if(nbytes != 10240)
{
pd->end_record = pd->rec_no+(int)(nbytes/pd->rec_len);
if(nbytes%pd->rec_len)
pd->end_record += 1;
lptr= pd->bigbuff+nbytes;
for(i=0;i< (int)(10240L-nbytes);i++)
*lptr++ = 0;
pd->bpos = 1;
}
else
pd->end_record = pd->rec_no - 5;
}
StartXRecord(pd->rec_len, pd->bigptr);
pd->bigptr += pd->rec_len;
if(pd->hDlg1)
{
pd->runcnt += pd->rec_len;
wsprintf( szBuffer,"%lu",pd->runcnt);
SetDlgItemText(pd->hDlg1,ID_BLKNO, szBuffer);
InvalidateRect(GetDlgItem(pd->hDlg1,ID_PERCENT),NULL,FALSE);
(*pd->TimeToGo) ();
}
pd->pcstate = IDX_WAITACK;
}
BOOL FileRxTX(int send, LPSTR ptr)
{
OFSTRUCT ofs;
lstrcpy(szBuffer,pd->szTempDir);
lstrcat(szBuffer,"\\");
lstrcat((LPSTR)szBuffer,ptr);
lstrcpy((LPSTR)pd->szRcvFile,ptr);
if(send==0)
{
if( (pd->hCommFile = OpenFile( (LPSTR)szBuffer, &ofs, OF_CREATE | OF_WRITE )) == -1)
{
StatusLine( IDS_LASTERROR+26,szBuffer);
*pd->aspfxfer=ASP_PROT_FAIL;
return( FALSE);
}
return(TRUE);
}
if( (pd->hCommFile = OpenFile( (LPSTR)szBuffer, &ofs, OF_READ )) == -1)
{
StatusLine( IDS_LASTERROR+24,szBuffer);
*pd->aspfxfer=ASP_PROT_FAIL;
return( FALSE);
}
pd->flen = filelength(pd->hCommFile);
pd->fdate = getfdate(pd->hCommFile);
pd->fftime = getftime(pd->hCommFile);
return(TRUE);
}